#include "microbabasse.h"
#include "ui_microbabasse.h"

MicroBabasse::MicroBabasse(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MicroBabasse)
{
    ui->setupUi(this);

    // On init le chemin de la base micro
    cheminbase = "microtmp.sqlite";


    // On vérifie la connexion
    if(QMessageBox::question(this,"Hors ligne","Etes vous connecté pour importer les proms?") == QMessageBox::Yes){
        // On récupère la base mysql
        db = QSqlDatabase::database("guest");
    } else {

        // On creer une base tmp
        QString cheminbasetmp = "promstmp.sqlite";
        QFile fichier(cheminbasetmp);
        if(fichier.exists()){
            fichier.remove();
        }

        db = QSqlDatabase::addDatabase("QSQLITE","promstmp");
        db.setHostName("localhost");
        db.setDatabaseName(cheminbasetmp);
        db.setUserName("root");
        db.setPassword("");
        if(db.open()){
            QSqlQuery q2("CREATE TABLE promotions (id INTEGER PRIMARY KEY AUTOINCREMENT, proms TEXT)",db);
            q2.exec();
            q2.finish();

            QSqlQuery q(db);
            q.prepare("INSERT INTO promotions (proms) VALUES (:p)");

            // On demande d'ajouter manuellement des proms
            bool complet = false;
            QStringList proms;
            QStringList centres;
            centres << "Ai" << "An" << "Bo" << "Ch" << "Cl" << "Li" << "Me" << "Ka";
            while(!complet){
                bool ok;
                QString centre = QInputDialog::getItem(this,"Centre","Selectionnez le centre",centres,0,false,&ok);
                int annee = QInputDialog::getInt(this,"Année","Selectionnez l'année",0,0,999,1,&ok);
                QString statut = QInputDialog::getText(this,"Statut","Donner le statut (P si perpet's, sinon laissez libre");
                if(ok){
                    if(QMessageBox::question(this,"Ajouter une proms","Voulez vous vraiment ajouter "+ centre + " "+ QString::number(annee) + statut +" à la liste des proms ?") == QMessageBox::Yes){
                        proms << centre + " " + QString::number(annee) + statut;
                        q.bindValue(":p",centre + " " + QString::number(annee) + statut);
                        q.exec();
                    }
                }

                if(QMessageBox::question(this,"Prom's","Les proms suivantes seront prises en compte :\n" + proms.join(" \n ") + "\nVoulez vous en ajouter ?") == QMessageBox::No){
                    complet = true;
                }
            }
            q.finish();

        }

    }

    // On défini que le fichier n'est pas ouvert pour vérouiller les appuis clavier
    fichierOuvert = false;

    // On désactive les champs inutiles
    ui->groupConso->setEnabled(false);
    ui->groupPromotions->setEnabled(false);
    ui->buttonAppliquer->setEnabled(false);
    ui->buttonImprimer->setEnabled(false);
    ui->buttonDemarrer->setEnabled(false);
    ui->tableBucquage->setEnabled(false);
    ui->buttonFermer->setEnabled(false);

    ui->buttonNouveau->setEnabled(true);
    ui->buttonOuvrir->setEnabled(true);

    // On init le model proms
    modelProms = PromsModel::allProms(db,this);
    ui->tableProms->setModel(modelProms);

    // On init la fenetre d'import
    import = new ConsoImport(this);
    import->hide();
    import->setWindowModality(Qt::WindowModal);
    import->setWindowFlags(Qt::Dialog);

    // On init les infos tmp
    famstmp = 0;
    promstmp = "";

}

MicroBabasse::~MicroBabasse()
{
    delete ui;
    delete import;
    delete modelBucquage;
    delete modelConsos;
    delete modelProms;
}

void MicroBabasse::importerConso(int id, QString nom, double prix)
{
    // Lors de la reception du signal d'import
    // On cherche la dernière ligne
    int row = modelConsos->rowCount();

    // On insère les informations dans la dernière ligne
    modelConsos->insertRow(row);
    modelConsos->setData(modelConsos->index(row,1),id);
    modelConsos->setData(modelConsos->index(row,2),nom);
    modelConsos->setData(modelConsos->index(row,3),prix);

    // On applique à la base micro
    if(!modelConsos->submitAll())
        QMessageBox::warning(this,"Erreur","La conso n'a pu être importée");

    return;
}

void MicroBabasse::nouveauPg()
{
    // Signaux de fin de la fenêtre de choix des consos

    // On revient sur la fenêtre choix Pg et on reset les fenêtre de choix
    choixconso->reset();
    choixconso->hide();
    choixpg->show();
    choixpg->setFocus();
    choixpg->reset();
}

void MicroBabasse::abandonner()
{
    // SIGNAL de fin de choix Pg

    // On remet les infos tmps a zéro
    famstmp = 0;
    promstmp = "";

    // On détruit les fenêtres de choix
    choixpg->hide();
    delete choixconso;
    delete choixpg;
}

void MicroBabasse::identifierPg(int fams, QString proms)
{
    // SIGNAL de choix pg

    // On stock le pg
    famstmp = fams;
    promstmp = proms;

    // On change de fenêtre
    choixpg->reset();
    choixpg->hide();
    choixconso->show();
    choixconso->setFocus();
}

void MicroBabasse::bucquer(QList<int> liste)
{
    // SIGNAL de choix des consos

    //Requête pour retrouver la bucque du pg (vérification)
    QSqlQuery q1(db);
    q1.prepare("SELECT bucque FROM v_users WHERE fams = :f AND proms = :p");
    q1.bindValue(":f",famstmp);
    q1.bindValue(":p",promstmp);
    q1.exec();
    q1.first();

    // Requete d'insertion des consos
    QSqlQuery q(microdb);
    q.prepare("INSERT INTO bucquage (bucque,fams,proms,idconso) VALUES (:b,:f,:p,:i)");
    q.bindValue(":f",famstmp);
    q.bindValue(":p",promstmp);
    q.bindValue(":b",q1.value(0).toString());

    // Insertion des consos
    for(int i = 0 ; i < liste.count() ; i++){
        q.bindValue(":i",liste.at(i));
        q.exec();
    }

    q.finish();

    q1.finish();

    // Raffraichi le tableau
    modelBucquage->select();
    ui->tableBucquage->resizeColumnsToContents();


    // On envoie le signal pour un nouveau pg
    nouveauPg();

}

void MicroBabasse::majProms(const QItemSelection &selected, const QItemSelection &deselected)
{

    // On retire les proms déselectionnées
    QSqlQuery q(microdb);
    q.prepare("DELETE FROM proms WHERE proms = :p");
    QModelIndexList l = deselected.indexes();
    for(int i =0;i<l.count();i++){
        q.bindValue(":p",modelProms->data(l.at(i)).toString());
        q.exec();
    }

    // On ajoute les proms sélectionnées
    q.prepare("INSERT INTO proms (proms) VALUES (:p)");
    l = selected.indexes();
    for(int i =0;i<l.count();i++){
        q.bindValue(":p",modelProms->data(l.at(i)).toString());
        q.exec();
    }
    q.finish();
}

void MicroBabasse::keyPressEvent(QKeyEvent *e)
{

    // ***************** Touches F0 *****************

    // On selectionne ou déselectionne en fonction de l'état de la proms voulue (en face de la touche appuyée)

    int k = e->key() - Qt::Key_F1;
    if(k>=0 && k<12 && k<modelProms->rowCount() && fichierOuvert){
        if(ui->tableProms->selectionModel()->isRowSelected(k,QModelIndex())){
            ui->tableProms->selectionModel()->select(modelProms->index(k,0),QItemSelectionModel::Deselect);
        }else{
            ui->tableProms->selectionModel()->select(modelProms->index(k,0),QItemSelectionModel::Select);
        }
    }

}

void MicroBabasse::on_buttonFermer_clicked()
{

    // Traitement pour la sauvegarde
        // On ferme la base
        microdb.close();
        QSqlDatabase::removeDatabase("microtmp");

        // On sauvegarde si fichier tmp
        if(cheminbase == "microtmp.sqlite"){


            if(QMessageBox::question(this,"Fichier temporaire","Voulez vous sauvegarder votre microbabasse (conseillé) ?") == QMessageBox::Yes){
                // Sauvegarde on-line ou locale
                QString save = QFileDialog::getSaveFileName(this,"Sauvegarde","","*.sqlite");

                // Copie du fichier temp ou envoi au serveur
                if(!QFile::copy(cheminbase,save)){
                    QMessageBox::critical(this,"Erreur","La sauvegarde a échouée.");
                    return;
                }
            }

            QFile::remove(cheminbase);
        }


        // ***

        // Efface les model
        delete modelBucquage;
        delete modelConsos;

        // Remise à zéro et désactivation de tous les champs

        fichierOuvert = false;

        ui->groupConso->setEnabled(false);
        ui->groupPromotions->setEnabled(false);
        ui->buttonAppliquer->setEnabled(false);
        ui->buttonImprimer->setEnabled(false);
        ui->buttonDemarrer->setEnabled(false);
        ui->tableBucquage->setEnabled(false);
        ui->buttonFermer->setEnabled(false);

        ui->buttonNouveau->setEnabled(true);
        ui->buttonOuvrir->setEnabled(true);


}


void MicroBabasse::on_buttonNouveau_clicked()
{

    // On créé une base tmp
    cheminbase = "microtmp.sqlite";
    QFile fichier(cheminbase);
    if(fichier.exists()){
        if(QMessageBox::question(this,"Fichier existant","Il existe déjà une micro babasse non sauvegardée. Voulez vous la supprimer?") == QMessageBox::No){
            return;
        }
        fichier.remove();
    }

    microdb = QSqlDatabase::addDatabase("QSQLITE","microtmp");
    microdb.setHostName("localhost");
    microdb.setDatabaseName(cheminbase);
    microdb.setUserName("root");
    microdb.setPassword("");
    if(microdb.open()){
        //Créer tables

        QSqlQuery q("CREATE TABLE consos (id INTEGER PRIMARY KEY AUTOINCREMENT, idreel INTEGER, nom TEXT, prix NUMERIC)",microdb);
        q.exec();
        q.finish();
        QSqlQuery q1("CREATE TABLE bucquage (id INTEGER PRIMARY KEY AUTOINCREMENT, bucque TEXT, fams NUMERIC, proms TEXT, idconso INTEGER)",microdb);
        q1.exec();
        q1.finish();
        QSqlQuery q2("CREATE TABLE proms (id INTEGER PRIMARY KEY AUTOINCREMENT, proms TEXT)",microdb);
        q2.exec();
        q2.finish();

        // On connecte les models
        connecterTemp();



    }
}

void MicroBabasse::connecterTemp()
{
    // Création des models

    modelConsos = new QSqlTableModel(this,microdb);
    modelConsos->setTable("consos");
    modelConsos->setEditStrategy(QSqlTableModel::OnManualSubmit);
    modelConsos->setHeaderData(0,Qt::Horizontal,"Id");
    modelConsos->setHeaderData(1,Qt::Horizontal,"Id");
    modelConsos->setHeaderData(2,Qt::Horizontal,"Nom");
    modelConsos->setHeaderData(3,Qt::Horizontal,"Prix");
    modelConsos->select();
    ui->tableConso->setModel(modelConsos);
    ui->tableConso->hideColumn(0);
    ui->tableConso->resizeColumnsToContents();


    modelBucquage = new QSqlRelationalTableModel(this,microdb);
    modelBucquage->setTable("bucquage");
    modelBucquage->setEditStrategy(QSqlTableModel::OnManualSubmit);
    modelBucquage->setHeaderData(0,Qt::Horizontal,"Id");
    modelBucquage->setHeaderData(1,Qt::Horizontal,"Bucque");
    modelBucquage->setHeaderData(2,Qt::Horizontal,"Fams");
    modelBucquage->setHeaderData(3,Qt::Horizontal,"Proms");
    modelBucquage->setHeaderData(4,Qt::Horizontal,"Conso");
    modelBucquage->setRelation(4,QSqlRelation("consos","id","nom"));
    modelBucquage->select();
    ui->tableBucquage->setModel(modelBucquage);
    ui->tableBucquage->hideColumn(0);
    ui->tableBucquage->resizeColumnsToContents();

    // Activation des widgets

    fichierOuvert = true;

    ui->groupConso->setEnabled(true);
    ui->groupPromotions->setEnabled(true);
    ui->buttonAppliquer->setEnabled(true);
    ui->buttonImprimer->setEnabled(true);
    ui->buttonDemarrer->setEnabled(true);
    ui->tableBucquage->setEnabled(true);
    ui->buttonFermer->setEnabled(true);

    ui->buttonNouveau->setEnabled(false);
    ui->buttonOuvrir->setEnabled(false);

    reloadProms();
}

void MicroBabasse::reloadProms()
{
    // Selection des proms
    QSqlQuery q(microdb);
    q.prepare("SELECT proms FROM proms");
    q.exec();
    QItemSelectionModel *m = new QItemSelectionModel(modelProms);
    m->clear();
    while (q.next()) {
        ui->tableProms->selectRow(modelProms->match(modelProms->index(0,0),Qt::DisplayRole,q.value(0).toString()).at(0).row());
    }
    connect(ui->tableProms->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)),this,SLOT(majProms(QItemSelection,QItemSelection)));

}

void MicroBabasse::on_buttonOuvrir_clicked()
{
    // Traitement de l'ouverture du fichier

        // Recherche du fichier
        cheminbase = QFileDialog::getOpenFileName(this,"Ouvrir","","*.sqlite");
        QFile fichier(cheminbase);
        if(!fichier.exists()){
            QMessageBox::warning(this,"Fichier non existant","Ce fichier n'existe pas");
            return;
        }

        // Connexion au fichier
        microdb = QSqlDatabase::addDatabase("QSQLITE","microtmp");
        microdb.setHostName("localhost");
        microdb.setDatabaseName(cheminbase);
        microdb.setUserName("root");
        microdb.setPassword("");
        if(microdb.open()){

            // Affichage des infos dans les vues
            connecterTemp();


        }

}

void MicroBabasse::on_buttonConsoAjouter_clicked()
{

    // On récupère les infos de la conso
    bool ok = false;

    QString nom = QInputDialog::getText(this,"Nouvelle conso","Tapez un nom pour la conso",QLineEdit::Normal,"",&ok);

    if(!ok)
        return;

    double prix = QInputDialog::getDouble(this,"Prix de la conso","Entrez le prix en euros",0.0,0.0,100.0,2,&ok);

    if(!ok)
        return;

    // On récupère la dernière ligne
    int row = modelConsos->rowCount();

    // On insère les infos à la fin
    modelConsos->insertRow(row);
    modelConsos->setData(modelConsos->index(row,1),0);
    modelConsos->setData(modelConsos->index(row,2),nom);
    modelConsos->setData(modelConsos->index(row,3),prix);

    // On applique les modifs
    if(!modelConsos->submitAll())
        QMessageBox::warning(this,"Erreur","La conso n'a pu être ajoutée");

    return;

}



void MicroBabasse::on_buttonConsoRetirer_clicked()
{
    // On retire la ligne selectionnée et on applique
    if(ui->tableConso->currentIndex().isValid()){
        modelConsos->removeRow(ui->tableConso->currentIndex().row());
        modelConsos->submitAll();
    }
}

void MicroBabasse::on_buttonConsoImport_clicked()
{
    // On connecte les signaux d'import
    connect(import,SIGNAL(finBucquage()),import,SLOT(hide()));
    connect(import,SIGNAL(finBucquage()),import,SLOT(reset()));
    connect(import,SIGNAL(bucquer(int,QString,double)),this,SLOT(importerConso(int,QString,double)));

    // On ouvre la fenêtre
    import->show();
}

void MicroBabasse::on_buttonSupprimer_clicked()
{
    // On retire la ligne selectionnée et on applique
    if(ui->tableBucquage->currentIndex().isValid()){
        modelBucquage->removeRow(ui->tableBucquage->currentIndex().row());
        modelBucquage->submitAll();
    }
}

void MicroBabasse::on_buttonDemarrer_clicked()
{

    // On créer les fenêtre de choix
    choixpg = new ChoixPg(this);
    choixconso = new ChoixConso(this);
    choixconso->hide();
    choixpg->hide();
    choixpg->setWindowModality(Qt::WindowModal);
    choixconso->setWindowModality(Qt::WindowModal);
    choixpg->setWindowFlags(Qt::Dialog);
    choixconso->setWindowFlags(Qt::Dialog);

    // On connecte les signaux
    connect(choixconso,SIGNAL(finBucquage()),this,SLOT(nouveauPg()));
    connect(choixconso,SIGNAL(bucquer(QList<int>)),this,SLOT(bucquer(QList<int>)));
    connect(choixpg,SIGNAL(bucquer(int,QString)),this,SLOT(identifierPg(int,QString)));
    connect(choixpg,SIGNAL(finBucquage()),this,SLOT(abandonner()));

    // On ouvre la choix pg
    choixpg->show();
}

void MicroBabasse::on_buttonAppliquer_clicked()
{
    // On récupère la catégorie racine
    QSettings s;
    int categorie_racine = s.value("categorie_racine").toInt();

    // On demande le mode
    bool consoMode = false;
    if(QMessageBox::question(this,"Mode d'enregistrement","Voulez-vous enregistrer cette babasse en mode conso (Yes) ou en mode transaction (No)",QMessageBox::Yes,QMessageBox::No) == QMessageBox::Yes)
        consoMode = true;

    QString user = consoMode ? "Moderateur" : "Tonton";

    // On connecte la base sur le bon mode
    ConnexionBDD::connexion(this,user);
    db = QSqlDatabase::database("user");

    // Après ouverture
    if(db.isOpen()){

        if(consoMode){
            // On insère dans la base toutes les nouvelles consos

            QSqlQuery q(db);
            q.prepare("INSERT INTO consos (categorie, nom, prix, actif) VALUES (:c,:n,:p,0)");
            q.bindValue(":c",categorie_racine);


            QSqlQuery q1(microdb);
            q1.prepare("SELECT * FROM consos WHERE idreel = 0");
            q1.exec();

            QSqlQuery q2(microdb);
            q2.prepare("UPDATE consos SET idreel = :r WHERE id = :i"); // Sans oublier de remettre à jour l'idreel

            while (q1.next()) {
                q.bindValue(":n",q1.value(2).toString());
                q.bindValue(":p",q1.value(3).toDouble());
                q.exec();

                q2.bindValue(":i",q1.value(0).toString());
                q2.bindValue(":r",q.lastInsertId().toInt());
                q2.exec();
            }

            q1.finish();

            q.finish();
            q2.finish();

            modelConsos->select();

            // On procède au bucquage

            q.prepare("CALL bucquer(:c,get_compte(:f,get_proms(:p)))");

            q1.prepare("SELECT b.fams, b.proms, c.idreel FROM bucquage AS b INNER JOIN consos AS c ON b.idconso = c.id");
            q1.exec();

            while(q1.next()){
                q.bindValue(":c",q1.value(2).toInt());
                q.bindValue(":f",q1.value(0).toInt());
                q.bindValue(":p",q1.value(1).toString());
                q.exec();
                if(q.numRowsAffected() <= 0)
                    QMessageBox::warning(this,"Erreur","Le compte "+q1.value(0).toString()+" "+q1.value(1).toString() + " n'a pas pu être bucqué");
            }
            q.finish();
            q1.finish();

            // On ferme la base micro
            on_buttonFermer_clicked();
            return;

        } else {

            // En mode transaction, on récupère le compte AE
            int compteAE = s.value("trans/compte").toInt();
            if(compteAE <= 0){
                QMessageBox::critical(this,"Compte non stipulé","Le compte AE n'est pas stipulé. Veuillez le renseigné dans l'onglet paramètre du programme Gestion_Transactions");
                return;
            }

            // On récupère le nom de la manip et on prépare le montant total
            double montantTotal = 0.0;
            QString transaction = QInputDialog::getText(this,"Nom de manip","Veuillez nommer la transaction (manip).");

            // On applique les transactions
            QSqlQuery q(db);
            q.prepare("CALL faire_transaction(get_compte(:f,get_proms(:p)),:c,:m,:l)");
            q.bindValue(":c",compteAE);
            q.bindValue(":l",transaction);

            QSqlQuery q1(microdb);
            q1.prepare("SELECT b.fams, b.proms, SUM(c.prix) FROM bucquage AS b INNER JOIN consos AS c ON b.idconso = c.id GROUP BY b.fams || b.proms");
            q1.exec();

            while(q1.next()){
                q.bindValue(":f",q1.value(0).toInt());
                q.bindValue(":p",q1.value(1).toString());
                q.bindValue(":m",q1.value(2).toDouble());

                q.exec();
                if(q.numRowsAffected() <= 0)
                    QMessageBox::warning(this,"Erreur","Le compte "+q1.value(0).toString()+" "+q1.value(1).toString() + " n'a pas pu être bucqué");
                else
                    montantTotal += q1.value(2).toDouble();
            }
            q.finish();
            q1.finish();

            // On renvoie le montant total
            QMessageBox::information(this,"Montant de la manip","Le compte AE à été crédité de "+QString::number(montantTotal,'f',2)+" €. N'oubliez pas de le signaler aux tontons.");

            // On ferme la base micro
            on_buttonFermer_clicked();
            return;


        }



    } else {
        QMessageBox::critical(this,"Erreur connexion","La connexion à la base n'a pu être établie. Vérifiez vos paramètres réseaux et réessayez.");
        return;
    }

}
